Một số package được sử dụng
# BASE
# ------------------------------------------------------
import numpy as np
import pandas as pd
import os
import gc
import warnings
# PACF - ACF
# ------------------------------------------------------
import statsmodels.api as sm
# DATA VISUALIZATION
# ------------------------------------------------------
import matplotlib.pyplot as plt
import seaborn as sns
import plotly.express as px
# CONFIGURATIONS
# ------------------------------------------------------
pd.set_option('display.max_columns', None)
pd.options.display.float_format = '{:.2f}'.format
warnings.filterwarnings('ignore')
# Import
train = pd.read_csv("D:/2021.2/store-sales-time-series-forecasting/train.csv")
test = pd.read_csv("D:/2021.2/store-sales-time-series-forecasting/test.csv")
stores = pd.read_csv("D:/2021.2/store-sales-time-series-forecasting/stores.csv")
#sub = pd.read_csv("../input/store-sales-time-series-forecasting/sample_submission.csv")
transactions = pd.read_csv("D:/2021.2/store-sales-time-series-forecasting/transactions.csv").sort_values(["store_nbr", "date"])
# Datetime
train["date"] = pd.to_datetime(train.date)
test["date"] = pd.to_datetime(test.date)
transactions["date"] = pd.to_datetime(transactions.date)
# Data types
train.onpromotion = train.onpromotion.astype("float16")
train.sales = train.sales.astype("float32")
stores.cluster = stores.cluster.astype("int8")
train.head()
| id | date | store_nbr | family | sales | onpromotion | |
|---|---|---|---|---|---|---|
| 0 | 0 | 2013-01-01 | 1 | AUTOMOTIVE | 0.00 | 0.00 |
| 1 | 1 | 2013-01-01 | 1 | BABY CARE | 0.00 | 0.00 |
| 2 | 2 | 2013-01-01 | 1 | BEAUTY | 0.00 | 0.00 |
| 3 | 3 | 2013-01-01 | 1 | BEVERAGES | 0.00 | 0.00 |
| 4 | 4 | 2013-01-01 | 1 | BOOKS | 0.00 | 0.00 |
Bắt đầu bằng các dữ liệu về giao dịch (Transactions)
transactions.head(10)
| date | store_nbr | transactions | |
|---|---|---|---|
| 1 | 2013-01-02 | 1 | 2111 |
| 47 | 2013-01-03 | 1 | 1833 |
| 93 | 2013-01-04 | 1 | 1863 |
| 139 | 2013-01-05 | 1 | 1509 |
| 185 | 2013-01-06 | 1 | 520 |
| 231 | 2013-01-07 | 1 | 1807 |
| 277 | 2013-01-08 | 1 | 1869 |
| 323 | 2013-01-09 | 1 | 1910 |
| 369 | 2013-01-10 | 1 | 1679 |
| 415 | 2013-01-11 | 1 | 1813 |
Thuộc tính này có mối tương quan cao với doanh số bán hàng nhưng trước tiên, ta phải tổng hợp tính năng bán hàng để tìm mối quan hệ. Giao dịch có nghĩa là có bao nhiêu người đến cửa hàng hoặc bao nhiêu hóa đơn được tạo trong một ngày.
Doanh số bán hàng cho biết tổng doanh số bán hàng cho một nhóm sản phẩm tại một cửa hàng cụ thể vào một ngày nhất định. Giá trị phân số là có thể vì sản phẩm có thể được bán theo đơn vị phân số (ví dụ: 1,5 kg pho mát, trái ngược với 1 túi khoai tây chiên).
Đó là lý do tại sao, các giao dịch sẽ là một trong những tính năng có liên quan trong mô hình. Trong các phần sau, ta sẽ tạo các tính năng mới bằng cách sử dụng các giao dịch.
temp = pd.merge(train.groupby(["date", "store_nbr"]).sales.sum().reset_index(), transactions, how = "left")
print("Spearman Correlation between Total Sales and Transactions: {:,.4f}".format(temp.corr("spearman").sales.loc["transactions"]))
px.line(transactions.sort_values(["store_nbr", "date"]), x='date', y='transactions', color='store_nbr',title = "Transactions" )
Spearman Correlation between Total Sales and Transactions: 0.8175
Ta thấy Giao dịch có một mô hình ổn định. Tất cả các tháng đều tương tự nhau ngoại trừ tháng 12 từ năm 2013 đến năm 2017 theo hình hộp. Ngoài ra, chúng ta vừa thấy một mẫu tương tự cho mỗi cửa hàng trong phần trước. Doanh thu của cửa hàng luôn tăng vào cuối năm.
a = transactions.copy()
a["year"] = a.date.dt.year
a["month"] = a.date.dt.month
px.box(a, x="year", y="transactions" , color = "month", title = "Transactions")
Hãy xem xét các giao dịch bằng cách sử dụng doanh số bán hàng trung bình hàng tháng
Ta vừa tìm ra một mô hình giúp tăng doanh số bán hàng. Đó là cuối năm. Chúng ta có thể thấy rằng các giao dịch tăng vào mùa xuân và giảm sau mùa xuân.
a = transactions.set_index("date").resample("M").transactions.mean().reset_index()
a["year"] = a.date.dt.year
px.line(a, x='date', y='transactions', color='year',title = "Monthly Average Transactions" )
Khi xem xét mối quan hệ của chúng, ta có thể thấy rằng có mối tương quan cao giữa tổng doanh số bán hàng và giao dịch.
px.scatter(temp, x = "transactions", y = "sales", trendline = "ols", trendline_color_override = "red")
Các ngày trong tuần rất quan trọng cho việc mua sắm. Các cửa hàng giao dịch nhiều hơn vào cuối tuần. Hầu hết, các mẫu đều giống nhau từ năm 2013 đến năm 2017 và thứ Bảy là ngày quan trọng nhất để mua sắm.
a = transactions.copy()
a["year"] = a.date.dt.year
a["dayofweek"] = a.date.dt.dayofweek+1
a = a.groupby(["year", "dayofweek"]).transactions.mean().reset_index()
px.line(a, x="dayofweek", y="transactions" , color = "year", title = "Transactions")
Nền kinh tế là một trong những vấn đề lớn nhất đối với chính phủ và người dân. Nó ảnh hưởng đến tất cả mọi thứ theo cách tốt hoặc xấu. Trong trường hợp ở đây, Ecuador là một quốc gia phụ thuộc vào dầu mỏ. Thay đổi giá dầu ở Ecuador sẽ gây ra sự khác biệt trong mô hình.
Có một số dữ liệu điểm bị thiếu trong dữ liệu dầu hàng ngày như có thể thấy bên dưới. Ta có thể xử lý dữ liệu bằng cách sử dụng các phương pháp imputation khác nhau. Tuy nhiên, ở đây tôi đã chọn một giải pháp đơn giản. Nội suy tuyến tính phù hợp với chuỗi thời gian này. Ta có thể thấy xu hướng và dự đoán các dữ liệu điểm còn thiếu khi nhìn vào biểu đồ thời gian của giá dầu.
# Import
oil = pd.read_csv("D:/2021.2/store-sales-time-series-forecasting/oil.csv")
oil["date"] = pd.to_datetime(oil.date)
# Resample
oil = oil.set_index("date").dcoilwtico.resample("D").sum().reset_index()
# Interpolate
oil["dcoilwtico"] = np.where(oil["dcoilwtico"] == 0, np.nan, oil["dcoilwtico"])
oil["dcoilwtico_interpolated"] =oil.dcoilwtico.interpolate()
# Plot
p = oil.melt(id_vars=['date']+list(oil.keys()[5:]), var_name='Legend')
px.line(p.sort_values(["Legend", "date"], ascending = [False, True]), x='date', y='value', color='Legend',title = "Daily Oil Price" )
"Ecuador là một quốc gia phụ thuộc vào dầu mỏ" nhưng sự thật có đúng như vậy không? Chúng ta có thể thực sự thấy điều đó từ dữ liệu bằng cách xem xét không?
Trước hết, chúng ta hãy xem xét các mối tương quan giữa doanh số và giao dịch. Các giá trị tương quan không mạnh nhưng dấu hiệu bán hàng là âm. Có lẽ, chúng ta có thể nắm bắt được một manh mối. Về mặt logic, nếu giá dầu hàng ngày cao, chúng tôi cho rằng nền kinh tế của Ecuador đang xấu và điều đó có nghĩa là giá sản phẩm tăng và doanh số bán hàng giảm, thể hiện một mối quan hệ nghịch biến ở đây.
temp = pd.merge(temp, oil, how = "left")
print("Correlation with Daily Oil Prices")
print(temp.drop(["store_nbr", "dcoilwtico"], axis = 1).corr("spearman").dcoilwtico_interpolated.loc[["sales", "transactions"]], "\n")
fig, axes = plt.subplots(1, 2, figsize = (15,5))
temp.plot.scatter(x = "dcoilwtico_interpolated", y = "transactions", ax=axes[0])
temp.plot.scatter(x = "dcoilwtico_interpolated", y = "sales", ax=axes[1], color = "r")
axes[0].set_title('Daily oil price & Transactions', fontsize = 15)
axes[1].set_title('Daily Oil Price & Sales', fontsize = 15);
Correlation with Daily Oil Prices sales -0.30 transactions 0.04 Name: dcoilwtico_interpolated, dtype: float64
Tuy nhiên, ta không nên quyết định mình sẽ làm gì bằng cách nhìn vào biểu đồ hoặc kết quả. Ta cần xác định các giả thuyết mới.
Sẽ là sai nếu chúng ta chỉ xem xét một số kết quả đầu ra đơn giản như trên và ta đã nói rằng không có mối quan hệ nào với giá dầu và quyết định không sử dụng dữ liệu giá dầu.
Ta sẽ phân tích sâu hơn nữa. Hãy vẽ một biểu đồ phân tán nhưng chúng ta hãy chú ý đến các họ sản phẩm lần này. Tất cả các ô gần như chứa cùng một mẫu. Khi giá dầu hàng ngày dưới 70, có nhiều doanh số bán hàng hơn trong dữ liệu. Có 2 cụm ở đây. Họ trên 70 và dưới 70. Thực ra thì có vẻ khá dễ hiểu.
Đây có thể là một cách tốt. Vừa rồi, chúng tôi không thể thấy mô hình giá dầu hàng ngày, nhưng bây giờ chúng tôi đã trích xuất một mô hình mới từ đó.
a = pd.merge(train.groupby(["date", "family"]).sales.sum().reset_index(), oil.drop("dcoilwtico", axis = 1), how = "left")
c = a.groupby("family").corr("spearman").reset_index()
c = c[c.level_1 == "dcoilwtico_interpolated"][["family", "sales"]].sort_values("sales")
fig, axes = plt.subplots(7, 5, figsize = (20,20))
for i, fam in enumerate(c.family):
if i < 6:
a[a.family == fam].plot.scatter(x = "dcoilwtico_interpolated", y = "sales", ax=axes[0, i-1])
axes[0, i-1].set_title(fam+"\n Correlation:"+str(c[c.family == fam].sales.iloc[0])[:6], fontsize = 12)
axes[0, i-1].axvline(x=70, color='r', linestyle='--')
if i >= 6 and i<11:
a[a.family == fam].plot.scatter(x = "dcoilwtico_interpolated", y = "sales", ax=axes[1, i-6])
axes[1, i-6].set_title(fam+"\n Correlation:"+str(c[c.family == fam].sales.iloc[0])[:6], fontsize = 12)
axes[1, i-6].axvline(x=70, color='r', linestyle='--')
if i >= 11 and i<16:
a[a.family == fam].plot.scatter(x = "dcoilwtico_interpolated", y = "sales", ax=axes[2, i-11])
axes[2, i-11].set_title(fam+"\n Correlation:"+str(c[c.family == fam].sales.iloc[0])[:6], fontsize = 12)
axes[2, i-11].axvline(x=70, color='r', linestyle='--')
if i >= 16 and i<21:
a[a.family == fam].plot.scatter(x = "dcoilwtico_interpolated", y = "sales", ax=axes[3, i-16])
axes[3, i-16].set_title(fam+"\n Correlation:"+str(c[c.family == fam].sales.iloc[0])[:6], fontsize = 12)
axes[3, i-16].axvline(x=70, color='r', linestyle='--')
if i >= 21 and i<26:
a[a.family == fam].plot.scatter(x = "dcoilwtico_interpolated", y = "sales", ax=axes[4, i-21])
axes[4, i-21].set_title(fam+"\n Correlation:"+str(c[c.family == fam].sales.iloc[0])[:6], fontsize = 12)
axes[4, i-21].axvline(x=70, color='r', linestyle='--')
if i >= 26 and i < 31:
a[a.family == fam].plot.scatter(x = "dcoilwtico_interpolated", y = "sales", ax=axes[5, i-26])
axes[5, i-26].set_title(fam+"\n Correlation:"+str(c[c.family == fam].sales.iloc[0])[:6], fontsize = 12)
axes[5, i-26].axvline(x=70, color='r', linestyle='--')
if i >= 31 :
a[a.family == fam].plot.scatter(x = "dcoilwtico_interpolated", y = "sales", ax=axes[6, i-31])
axes[6, i-31].set_title(fam+"\n Correlation:"+str(c[c.family == fam].sales.iloc[0])[:6], fontsize = 12)
axes[6, i-31].axvline(x=70, color='r', linestyle='--')
plt.tight_layout(pad=5)
plt.suptitle("Daily Oil Product & Total Family Sales \n", fontsize = 20);
plt.show()
Mục tiêu chính của ta là dự đoán doanh số bán hàng của cửa hàng cho từng dòng sản phẩm. Vì lý do này, cột bán hàng nên được kiểm tra nghiêm túc hơn. Chúng ta cần tìm hiểu mọi thứ như tính thời vụ, xu hướng, sự bất thường, điểm tương đồng với các chuỗi thời gian khác.
Hầu hết các cửa hàng đều tương tự nhau, khi ta kiểm tra chúng bằng ma trận tương quan. Một số cửa hàng, chẳng hạn như 20, 21, 22 và 52 có thể hơi khác một chút.
a = train[["store_nbr", "sales"]]
a["ind"] = 1
a["ind"] = a.groupby("store_nbr").ind.cumsum().values
a = pd.pivot(a, index = "ind", columns = "store_nbr", values = "sales").corr()
mask = np.triu(a.corr())
plt.figure(figsize=(20, 20))
sns.heatmap(a,
annot=True,
fmt='.1f',
cmap='coolwarm',
square=True,
mask=mask,
linewidths=1,
cbar=False)
plt.title("Correlations among stores",fontsize = 20)
plt.show()
Dưới đây là biểu đồ cho ta biết doanh thu mỗi ngày
a = train.set_index("date").groupby("store_nbr").resample("D").sales.sum().reset_index()
px.line(a, x = "date", y= "sales", color = "store_nbr", title = "Daily total sales of the stores")
Ta nhận ra một số hàng không cần thiết trong dữ liệu khi đang xem xét chuỗi thời gian của từng cửa hàng một. Nếu chọn các cửa hàng từ trên xuống, một số trong số đó không có doanh số bán hàng vào đầu năm 2013. Ta có thể thấy chúng nếu nhìn vào các cửa hàng 20, 21, 22, 29, 36, 42, 52 và 53. Ta quyết định để loại bỏ các hàng đó trước khi các cửa hàng mở cửa. Trong các mã sau, ta sẽ loại bỏ chúng.
print(train.shape)
train = train[~((train.store_nbr == 52) & (train.date < "2017-04-20"))]
train = train[~((train.store_nbr == 22) & (train.date < "2015-10-09"))]
train = train[~((train.store_nbr == 42) & (train.date < "2015-08-21"))]
train = train[~((train.store_nbr == 21) & (train.date < "2015-07-24"))]
train = train[~((train.store_nbr == 29) & (train.date < "2015-03-20"))]
train = train[~((train.store_nbr == 20) & (train.date < "2015-02-13"))]
train = train[~((train.store_nbr == 53) & (train.date < "2014-05-29"))]
train = train[~((train.store_nbr == 36) & (train.date < "2013-05-09"))]
train.shape
(3000888, 6)
(2780316, 6)
Một số cửa hàng không bán một số họ sản phẩm. Trong đoạn code sau, ta có thể thấy sản phẩm nào không được bán ở những cửa hàng nào. Không khó để dự báo chúng trong 15 ngày tới. Dự báo của họ phải là 0 trong 15 ngày tới.
Ta sẽ xóa chúng khỏi dữ liệu và tạo khung dữ liệu mới cho các nhóm sản phẩm không bao giờ bán. Sau đó, khi chúng ta đang ở phần nộp hồ sơ, ta sẽ kết hợp khung dữ liệu đó với các dự đoán của chúng ta.
c = train.groupby(["store_nbr", "family"]).sales.sum().reset_index().sort_values(["family","store_nbr"])
c = c[c.sales == 0]
c
| store_nbr | family | sales | |
|---|---|---|---|
| 1 | 1 | BABY CARE | 0.00 |
| 397 | 13 | BABY CARE | 0.00 |
| 727 | 23 | BABY CARE | 0.00 |
| 1420 | 44 | BABY CARE | 0.00 |
| 1453 | 45 | BABY CARE | 0.00 |
| 1486 | 46 | BABY CARE | 0.00 |
| 1519 | 47 | BABY CARE | 0.00 |
| 1552 | 48 | BABY CARE | 0.00 |
| 1585 | 49 | BABY CARE | 0.00 |
| 1618 | 50 | BABY CARE | 0.00 |
| 1651 | 51 | BABY CARE | 0.00 |
| 1684 | 52 | BABY CARE | 0.00 |
| 268 | 9 | BOOKS | 0.00 |
| 301 | 10 | BOOKS | 0.00 |
| 334 | 11 | BOOKS | 0.00 |
| 367 | 12 | BOOKS | 0.00 |
| 400 | 13 | BOOKS | 0.00 |
| 433 | 14 | BOOKS | 0.00 |
| 466 | 15 | BOOKS | 0.00 |
| 499 | 16 | BOOKS | 0.00 |
| 532 | 17 | BOOKS | 0.00 |
| 565 | 18 | BOOKS | 0.00 |
| 598 | 19 | BOOKS | 0.00 |
| 631 | 20 | BOOKS | 0.00 |
| 664 | 21 | BOOKS | 0.00 |
| 697 | 22 | BOOKS | 0.00 |
| 895 | 28 | BOOKS | 0.00 |
| 928 | 29 | BOOKS | 0.00 |
| 961 | 30 | BOOKS | 0.00 |
| 994 | 31 | BOOKS | 0.00 |
| 1027 | 32 | BOOKS | 0.00 |
| 1060 | 33 | BOOKS | 0.00 |
| 1093 | 34 | BOOKS | 0.00 |
| 1126 | 35 | BOOKS | 0.00 |
| 1159 | 36 | BOOKS | 0.00 |
| 1258 | 39 | BOOKS | 0.00 |
| 1291 | 40 | BOOKS | 0.00 |
| 1390 | 43 | BOOKS | 0.00 |
| 1687 | 52 | BOOKS | 0.00 |
| 1753 | 54 | BOOKS | 0.00 |
| 514 | 16 | LADIESWEAR | 0.00 |
| 811 | 25 | LADIESWEAR | 0.00 |
| 910 | 28 | LADIESWEAR | 0.00 |
| 943 | 29 | LADIESWEAR | 0.00 |
| 1042 | 32 | LADIESWEAR | 0.00 |
| 1075 | 33 | LADIESWEAR | 0.00 |
| 1141 | 35 | LADIESWEAR | 0.00 |
| 1306 | 40 | LADIESWEAR | 0.00 |
| 1405 | 43 | LADIESWEAR | 0.00 |
| 1768 | 54 | LADIESWEAR | 0.00 |
| 449 | 14 | LAWN AND GARDEN | 0.00 |
| 977 | 30 | LAWN AND GARDEN | 0.00 |
| 1769 | 54 | LAWN AND GARDEN | 0.00 |
print(train.shape)
# Anti Join
outer_join = train.merge(c[c.sales == 0].drop("sales",axis = 1), how = 'outer', indicator = True)
train = outer_join[~(outer_join._merge == 'both')].drop('_merge', axis = 1)
del outer_join
gc.collect()
train.shape
(2780316, 6)
(2698648, 6)
zero_prediction = []
for i in range(0,len(c)):
zero_prediction.append(
pd.DataFrame({
"date":pd.date_range("2017-08-16", "2017-08-31").tolist(),
"store_nbr":c.store_nbr.iloc[i],
"family":c.family.iloc[i],
"sales":0
})
)
zero_prediction = pd.concat(zero_prediction)
del c
gc.collect()
zero_prediction
| date | store_nbr | family | sales | |
|---|---|---|---|---|
| 0 | 2017-08-16 | 1 | BABY CARE | 0 |
| 1 | 2017-08-17 | 1 | BABY CARE | 0 |
| 2 | 2017-08-18 | 1 | BABY CARE | 0 |
| 3 | 2017-08-19 | 1 | BABY CARE | 0 |
| 4 | 2017-08-20 | 1 | BABY CARE | 0 |
| ... | ... | ... | ... | ... |
| 11 | 2017-08-27 | 54 | LAWN AND GARDEN | 0 |
| 12 | 2017-08-28 | 54 | LAWN AND GARDEN | 0 |
| 13 | 2017-08-29 | 54 | LAWN AND GARDEN | 0 |
| 14 | 2017-08-30 | 54 | LAWN AND GARDEN | 0 |
| 15 | 2017-08-31 | 54 | LAWN AND GARDEN | 0 |
848 rows × 4 columns
Một số sản phẩm hiếm khi có thể bán được trong các cửa hàng. Ta sẽ xem xét trong 60 ngày qua.
Một số loại sản phẩm phụ thuộc vào thời vụ. Một số trong số đó có thể không hoạt động trong 60 ngày qua nhưng không có nghĩa là nó không hoạt động.
c = train.groupby(["family", "store_nbr"]).tail(60).groupby(["family", "store_nbr"]).sales.sum().reset_index()
c[c.sales == 0]
| family | store_nbr | sales | |
|---|---|---|---|
| 54 | BABY CARE | 2 | 0.00 |
| 62 | BABY CARE | 10 | 0.00 |
| 64 | BABY CARE | 12 | 0.00 |
| 65 | BABY CARE | 14 | 0.00 |
| 76 | BABY CARE | 26 | 0.00 |
| 82 | BABY CARE | 32 | 0.00 |
| 83 | BABY CARE | 33 | 0.00 |
| 87 | BABY CARE | 37 | 0.00 |
| 88 | BABY CARE | 38 | 0.00 |
| 92 | BABY CARE | 42 | 0.00 |
| 95 | BABY CARE | 54 | 0.00 |
| 205 | BOOKS | 2 | 0.00 |
| 206 | BOOKS | 3 | 0.00 |
| 208 | BOOKS | 5 | 0.00 |
| 209 | BOOKS | 6 | 0.00 |
| 214 | BOOKS | 25 | 0.00 |
| 215 | BOOKS | 26 | 0.00 |
| 217 | BOOKS | 37 | 0.00 |
| 219 | BOOKS | 41 | 0.00 |
| 220 | BOOKS | 42 | 0.00 |
| 229 | BOOKS | 53 | 0.00 |
| 1014 | LADIESWEAR | 36 | 0.00 |
| 1039 | LAWN AND GARDEN | 10 | 0.00 |
| 1041 | LAWN AND GARDEN | 12 | 0.00 |
| 1042 | LAWN AND GARDEN | 13 | 0.00 |
| 1043 | LAWN AND GARDEN | 15 | 0.00 |
| 1044 | LAWN AND GARDEN | 16 | 0.00 |
| 1045 | LAWN AND GARDEN | 17 | 0.00 |
| 1047 | LAWN AND GARDEN | 19 | 0.00 |
| 1050 | LAWN AND GARDEN | 22 | 0.00 |
| 1059 | LAWN AND GARDEN | 32 | 0.00 |
| 1060 | LAWN AND GARDEN | 33 | 0.00 |
| 1062 | LAWN AND GARDEN | 35 | 0.00 |
| 1621 | SCHOOL AND OFFICE SUPPLIES | 1 | 0.00 |
| 1622 | SCHOOL AND OFFICE SUPPLIES | 2 | 0.00 |
| 1626 | SCHOOL AND OFFICE SUPPLIES | 6 | 0.00 |
| 1636 | SCHOOL AND OFFICE SUPPLIES | 16 | 0.00 |
| 1643 | SCHOOL AND OFFICE SUPPLIES | 23 | 0.00 |
| 1644 | SCHOOL AND OFFICE SUPPLIES | 24 | 0.00 |
| 1652 | SCHOOL AND OFFICE SUPPLIES | 32 | 0.00 |
| 1653 | SCHOOL AND OFFICE SUPPLIES | 33 | 0.00 |
| 1660 | SCHOOL AND OFFICE SUPPLIES | 40 | 0.00 |
| 1674 | SCHOOL AND OFFICE SUPPLIES | 54 | 0.00 |
Như ta có thể thấy bên dưới, những ví dụ này quá hiếm và doanh số bán hàng cũng thấp. Ta sẽ tạo ra một tính năng mới. Nó cho thấy rằng họ sản phẩm đang hoạt động hay không.
fig, ax = plt.subplots(1,5, figsize = (20,4))
train[(train.store_nbr == 10) & (train.family == "LAWN AND GARDEN")].set_index("date").sales.plot(ax = ax[0], title = "STORE 10 - LAWN AND GARDEN")
train[(train.store_nbr == 36) & (train.family == "LADIESWEAR")].set_index("date").sales.plot(ax = ax[1], title = "STORE 36 - LADIESWEAR")
train[(train.store_nbr == 6) & (train.family == "SCHOOL AND OFFICE SUPPLIES")].set_index("date").sales.plot(ax = ax[2], title = "STORE 6 - SCHOOL AND OFFICE SUPPLIES")
train[(train.store_nbr == 14) & (train.family == "BABY CARE")].set_index("date").sales.plot(ax = ax[3], title = "STORE 14 - BABY CARE")
train[(train.store_nbr == 53) & (train.family == "BOOKS")].set_index("date").sales.plot(ax = ax[4], title = "STORE 43 - BOOKS")
plt.show()
Chúng ta có thể nắm bắt được xu hướng, tính thời vụ và sự bất thường của các họ.
a = train.set_index("date").groupby("family").resample("D").sales.sum().reset_index()
px.line(a, x = "date", y= "sales", color = "family", title = "Daily total sales of the family")
Ta quan sát các cửa hàng. Có rất nhiều sản phẩm trong các cửa hàng và chúng ta cần biết họ sản phẩm nào bán nhiều hơn. Chúng ta hãy làm một mô hình để xem điều đó.
Biểu đồ cho chúng ta thấy GROCERY I và BEVERAGES là những gia đình bán chạy nhất.
a = train.groupby("family").sales.mean().sort_values(ascending = False).reset_index()
px.bar(a, y = "family", x="sales", color = "family", title = "Which product family preferred more?")
Các cửa hàng có thể khác nhau như thế nào? Ta thực sự chưa tìm thấy một mô hình chính cho các cửa hàng. Nhưng ta mới chỉ quan sát một biểu đồ duy nhất. Có thể có một số mô hình tiềm ẩn mà ta chưa thấy.
d = pd.merge(train, stores)
d["store_nbr"] = d["store_nbr"].astype("int8")
d["year"] = d.date.dt.year
px.line(d.groupby(["city", "year"]).sales.mean().reset_index(), x = "year", y = "sales", color = "city")
Dữ liệu ngày lễ và sự kiện chứa rất nhiều thông tin bên trong. Nó là một siêu dữ liệu nên ta phải phân chia nó một cách hợp lý và làm cho dữ liệu trở nên hữu ích.
Vấn đề của chúng ta là gì?
holidays = pd.read_csv("D:/2021.2/store-sales-time-series-forecasting/holidays_events.csv")
holidays["date"] = pd.to_datetime(holidays.date)
# holidays[holidays.type == "Holiday"]
# holidays[(holidays.type == "Holiday") & (holidays.transferred == True)]
# Transferred Holidays
tr1 = holidays[(holidays.type == "Holiday") & (holidays.transferred == True)].drop("transferred", axis = 1).reset_index(drop = True)
tr2 = holidays[(holidays.type == "Transfer")].drop("transferred", axis = 1).reset_index(drop = True)
tr = pd.concat([tr1,tr2], axis = 1)
tr = tr.iloc[:, [5,1,2,3,4]]
holidays = holidays[(holidays.transferred == False) & (holidays.type != "Transfer")].drop("transferred", axis = 1)
holidays = holidays.append(tr).reset_index(drop = True)
# Additional Holidays
holidays["description"] = holidays["description"].str.replace("-", "").str.replace("+", "").str.replace('\d+', '')
holidays["type"] = np.where(holidays["type"] == "Additional", "Holiday", holidays["type"])
# Bridge Holidays
holidays["description"] = holidays["description"].str.replace("Puente ", "")
holidays["type"] = np.where(holidays["type"] == "Bridge", "Holiday", holidays["type"])
# Work Day Holidays, that is meant to payback the Bridge.
work_day = holidays[holidays.type == "Work Day"]
holidays = holidays[holidays.type != "Work Day"]
# Split
# Events are national
events = holidays[holidays.type == "Event"].drop(["type", "locale", "locale_name"], axis = 1).rename({"description":"events"}, axis = 1)
holidays = holidays[holidays.type != "Event"].drop("type", axis = 1)
regional = holidays[holidays.locale == "Regional"].rename({"locale_name":"state", "description":"holiday_regional"}, axis = 1).drop("locale", axis = 1).drop_duplicates()
national = holidays[holidays.locale == "National"].rename({"description":"holiday_national"}, axis = 1).drop(["locale", "locale_name"], axis = 1).drop_duplicates()
local = holidays[holidays.locale == "Local"].rename({"description":"holiday_local", "locale_name":"city"}, axis = 1).drop("locale", axis = 1).drop_duplicates()
d = pd.merge(train.append(test), stores)
d["store_nbr"] = d["store_nbr"].astype("int8")
# National Holidays & Events
#d = pd.merge(d, events, how = "left")
d = pd.merge(d, national, how = "left")
# Regional
d = pd.merge(d, regional, how = "left", on = ["date", "state"])
# Local
d = pd.merge(d, local, how = "left", on = ["date", "city"])
# Work Day: It will be removed when real work day colum created
d = pd.merge(d, work_day[["date", "type"]].rename({"type":"IsWorkDay"}, axis = 1),how = "left")
# EVENTS
events["events"] =np.where(events.events.str.contains("futbol"), "Futbol", events.events)
def one_hot_encoder(df, nan_as_category=True):
original_columns = list(df.columns)
categorical_columns = df.select_dtypes(["category", "object"]).columns.tolist()
# categorical_columns = [col for col in df.columns if df[col].dtype == 'object']
df = pd.get_dummies(df, columns=categorical_columns, dummy_na=nan_as_category)
new_columns = [c for c in df.columns if c not in original_columns]
df.columns = df.columns.str.replace(" ", "_")
return df, df.columns.tolist()
events, events_cat = one_hot_encoder(events, nan_as_category=False)
events["events_Dia_de_la_Madre"] = np.where(events.date == "2016-05-08", 1,events["events_Dia_de_la_Madre"])
events = events.drop(239)
d = pd.merge(d, events, how = "left")
d[events_cat] = d[events_cat].fillna(0)
# New features
d["holiday_national_binary"] = np.where(d.holiday_national.notnull(), 1, 0)
d["holiday_local_binary"] = np.where(d.holiday_local.notnull(), 1, 0)
d["holiday_regional_binary"] = np.where(d.holiday_regional.notnull(), 1, 0)
#
d["national_independence"] = np.where(d.holiday_national.isin(['Batalla de Pichincha', 'Independencia de Cuenca', 'Independencia de Guayaquil', 'Independencia de Guayaquil', 'Primer Grito de Independencia']), 1, 0)
d["local_cantonizacio"] = np.where(d.holiday_local.str.contains("Cantonizacio"), 1, 0)
d["local_fundacion"] = np.where(d.holiday_local.str.contains("Fundacion"), 1, 0)
d["local_independencia"] = np.where(d.holiday_local.str.contains("Independencia"), 1, 0)
holidays, holidays_cat = one_hot_encoder(d[["holiday_national","holiday_regional","holiday_local"]], nan_as_category=False)
d = pd.concat([d.drop(["holiday_national","holiday_regional","holiday_local"], axis = 1),holidays], axis = 1)
he_cols = d.columns[d.columns.str.startswith("events")].tolist() + d.columns[d.columns.str.startswith("holiday")].tolist() + d.columns[d.columns.str.startswith("national")].tolist()+ d.columns[d.columns.str.startswith("local")].tolist()
d[he_cols] = d[he_cols].astype("int8")
d[["family", "city", "state", "type"]] = d[["family", "city", "state", "type"]].astype("category")
del holidays, holidays_cat, work_day, local, regional, national, events, events_cat, tr, tr1, tr2, he_cols
gc.collect()
d.head(10)
| id | date | store_nbr | family | sales | onpromotion | city | state | type | cluster | IsWorkDay | events_Black_Friday | events_Cyber_Monday | events_Dia_de_la_Madre | events_Futbol | events_Terremoto_Manabi | holiday_national_binary | holiday_local_binary | holiday_regional_binary | national_independence | local_cantonizacio | local_fundacion | local_independencia | holiday_national_Batalla_de_Pichincha | holiday_national_Carnaval | holiday_national_Dia_de_Difuntos | holiday_national_Dia_de_la_Madre | holiday_national_Dia_del_Trabajo | holiday_national_Independencia_de_Cuenca | holiday_national_Independencia_de_Guayaquil | holiday_national_Navidad | holiday_national_Primer_Grito_de_Independencia | holiday_national_Primer_dia_del_ano | holiday_national_Viernes_Santo | holiday_regional_Provincializacion_Santa_Elena | holiday_regional_Provincializacion_de_Cotopaxi | holiday_regional_Provincializacion_de_Imbabura | holiday_regional_Provincializacion_de_Santo_Domingo | holiday_local_Cantonizacion_de_Cayambe | holiday_local_Cantonizacion_de_El_Carmen | holiday_local_Cantonizacion_de_Guaranda | holiday_local_Cantonizacion_de_Latacunga | holiday_local_Cantonizacion_de_Libertad | holiday_local_Cantonizacion_de_Quevedo | holiday_local_Cantonizacion_de_Riobamba | holiday_local_Cantonizacion_de_Salinas | holiday_local_Cantonizacion_del_Puyo | holiday_local_Fundacion_de_Ambato | holiday_local_Fundacion_de_Cuenca | holiday_local_Fundacion_de_Esmeraldas | holiday_local_Fundacion_de_Guayaquil | holiday_local_Fundacion_de_Ibarra | holiday_local_Fundacion_de_Loja | holiday_local_Fundacion_de_Machala | holiday_local_Fundacion_de_Manta | holiday_local_Fundacion_de_Quito | holiday_local_Fundacion_de_Riobamba | holiday_local_Fundacion_de_Santo_Domingo | holiday_local_Independencia_de_Ambato | holiday_local_Independencia_de_Guaranda | holiday_local_Independencia_de_Latacunga | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 0 | 2013-01-01 | 1 | AUTOMOTIVE | 0.00 | 0.00 | Quito | Pichincha | D | 13 | NaN | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 1 | 1782 | 2013-01-02 | 1 | AUTOMOTIVE | 2.00 | 0.00 | Quito | Pichincha | D | 13 | NaN | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 2 | 3564 | 2013-01-03 | 1 | AUTOMOTIVE | 3.00 | 0.00 | Quito | Pichincha | D | 13 | NaN | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 3 | 5346 | 2013-01-04 | 1 | AUTOMOTIVE | 3.00 | 0.00 | Quito | Pichincha | D | 13 | NaN | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 4 | 7128 | 2013-01-05 | 1 | AUTOMOTIVE | 5.00 | 0.00 | Quito | Pichincha | D | 13 | Work Day | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 5 | 8910 | 2013-01-06 | 1 | AUTOMOTIVE | 2.00 | 0.00 | Quito | Pichincha | D | 13 | NaN | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 6 | 10692 | 2013-01-07 | 1 | AUTOMOTIVE | 0.00 | 0.00 | Quito | Pichincha | D | 13 | NaN | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 7 | 12474 | 2013-01-08 | 1 | AUTOMOTIVE | 2.00 | 0.00 | Quito | Pichincha | D | 13 | NaN | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 8 | 14256 | 2013-01-09 | 1 | AUTOMOTIVE | 2.00 | 0.00 | Quito | Pichincha | D | 13 | NaN | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 9 | 16038 | 2013-01-10 | 1 | AUTOMOTIVE | 2.00 | 0.00 | Quito | Pichincha | D | 13 | NaN | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
Áp dụng bài test A/B cho các thuộc tính Sự kiện và Ngày lễ. Chúng có ý nghĩa thống kê không? Ngoài ra, nó có thể là một cách tốt để lựa chọn tính năng đầu tiên.
def AB_Test(dataframe, group, target):
# Packages
from scipy.stats import shapiro
import scipy.stats as stats
# Split A/B
groupA = dataframe[dataframe[group] == 1][target]
groupB = dataframe[dataframe[group] == 0][target]
# Assumption: Normality
ntA = shapiro(groupA)[1] < 0.05
ntB = shapiro(groupB)[1] < 0.05
# H0: Distribution is Normal! - False
# H1: Distribution is not Normal! - True
if (ntA == False) & (ntB == False): # "H0: Normal Distribution"
# Parametric Test
# Assumption: Homogeneity of variances
leveneTest = stats.levene(groupA, groupB)[1] < 0.05
# H0: Homogeneity: False
# H1: Heterogeneous: True
if leveneTest == False:
# Homogeneity
ttest = stats.ttest_ind(groupA, groupB, equal_var=True)[1]
# H0: M1 == M2 - False
# H1: M1 != M2 - True
else:
# Heterogeneous
ttest = stats.ttest_ind(groupA, groupB, equal_var=False)[1]
# H0: M1 == M2 - False
# H1: M1 != M2 - True
else:
# Non-Parametric Test
ttest = stats.mannwhitneyu(groupA, groupB)[1]
# H0: M1 == M2 - False
# H1: M1 != M2 - True
# Result
temp = pd.DataFrame({
"AB Hypothesis":[ttest < 0.05],
"p-value":[ttest]
})
temp["Test Type"] = np.where((ntA == False) & (ntB == False), "Parametric", "Non-Parametric")
temp["AB Hypothesis"] = np.where(temp["AB Hypothesis"] == False, "Fail to Reject H0", "Reject H0")
temp["Comment"] = np.where(temp["AB Hypothesis"] == "Fail to Reject H0", "A/B groups are similar!", "A/B groups are not similar!")
temp["Feature"] = group
temp["GroupA_mean"] = groupA.mean()
temp["GroupB_mean"] = groupB.mean()
temp["GroupA_median"] = groupA.median()
temp["GroupB_median"] = groupB.median()
# Columns
if (ntA == False) & (ntB == False):
temp["Homogeneity"] = np.where(leveneTest == False, "Yes", "No")
temp = temp[["Feature","Test Type", "Homogeneity","AB Hypothesis", "p-value", "Comment", "GroupA_mean", "GroupB_mean", "GroupA_median", "GroupB_median"]]
else:
temp = temp[["Feature","Test Type","AB Hypothesis", "p-value", "Comment", "GroupA_mean", "GroupB_mean", "GroupA_median", "GroupB_median"]]
# Print Hypothesis
# print("# A/B Testing Hypothesis")
# print("H0: A == B")
# print("H1: A != B", "\n")
return temp
# Apply A/B Testing
he_cols = d.columns[d.columns.str.startswith("events")].tolist() + d.columns[d.columns.str.startswith("holiday")].tolist() + d.columns[d.columns.str.startswith("national")].tolist()+ d.columns[d.columns.str.startswith("local")].tolist()
ab = []
for i in he_cols:
ab.append(AB_Test(dataframe=d[d.sales.notnull()], group = i, target = "sales"))
ab = pd.concat(ab)
ab
| Feature | Test Type | AB Hypothesis | p-value | Comment | GroupA_mean | GroupB_mean | GroupA_median | GroupB_median | |
|---|---|---|---|---|---|---|---|---|---|
| 0 | events_Black_Friday | Non-Parametric | Reject H0 | 0.00 | A/B groups are not similar! | 393.70 | 396.72 | 26.58 | 19.00 |
| 0 | events_Cyber_Monday | Non-Parametric | Reject H0 | 0.00 | A/B groups are not similar! | 472.65 | 396.57 | 24.00 | 19.00 |
| 0 | events_Dia_de_la_Madre | Non-Parametric | Reject H0 | 0.00 | A/B groups are not similar! | 386.35 | 396.74 | 17.00 | 19.00 |
| 0 | events_Futbol | Non-Parametric | Reject H0 | 0.00 | A/B groups are not similar! | 360.30 | 397.01 | 13.00 | 19.00 |
| 0 | events_Terremoto_Manabi | Non-Parametric | Reject H0 | 0.00 | A/B groups are not similar! | 519.38 | 394.30 | 30.00 | 19.00 |
| 0 | holiday_national_binary | Non-Parametric | Reject H0 | 0.00 | A/B groups are not similar! | 471.40 | 393.15 | 20.00 | 19.00 |
| 0 | holiday_local_binary | Non-Parametric | Reject H0 | 0.00 | A/B groups are not similar! | 472.89 | 396.41 | 24.00 | 19.00 |
| 0 | holiday_regional_binary | Non-Parametric | Reject H0 | 0.00 | A/B groups are not similar! | 254.61 | 396.76 | 11.00 | 19.00 |
| 0 | holiday_national_Batalla_de_Pichincha | Non-Parametric | Fail to Reject H0 | 0.62 | A/B groups are similar! | 434.22 | 396.60 | 21.00 | 19.00 |
| 0 | holiday_national_Carnaval | Non-Parametric | Fail to Reject H0 | 0.19 | A/B groups are similar! | 373.36 | 396.86 | 19.00 | 19.00 |
| 0 | holiday_national_Dia_de_Difuntos | Non-Parametric | Reject H0 | 0.00 | A/B groups are not similar! | 471.98 | 396.49 | 26.00 | 19.00 |
| 0 | holiday_national_Dia_de_la_Madre | Non-Parametric | Reject H0 | 0.00 | A/B groups are not similar! | 495.64 | 396.42 | 30.00 | 19.00 |
| 0 | holiday_national_Dia_del_Trabajo | Non-Parametric | Reject H0 | 0.00 | A/B groups are not similar! | 535.81 | 396.30 | 23.00 | 19.00 |
| 0 | holiday_national_Independencia_de_Cuenca | Non-Parametric | Reject H0 | 0.00 | A/B groups are not similar! | 528.54 | 396.40 | 23.37 | 19.00 |
| 0 | holiday_national_Independencia_de_Guayaquil | Non-Parametric | Reject H0 | 0.00 | A/B groups are not similar! | 476.40 | 396.52 | 27.00 | 19.00 |
| 0 | holiday_national_Navidad | Non-Parametric | Reject H0 | 0.00 | A/B groups are not similar! | 607.37 | 394.18 | 36.49 | 19.00 |
| 0 | holiday_national_Primer_Grito_de_Independencia | Non-Parametric | Reject H0 | 0.02 | A/B groups are not similar! | 407.43 | 396.68 | 22.00 | 19.00 |
| 0 | holiday_national_Primer_dia_del_ano | Non-Parametric | Reject H0 | 0.00 | A/B groups are not similar! | 347.77 | 397.00 | 0.00 | 19.00 |
| 0 | holiday_national_Viernes_Santo | Non-Parametric | Reject H0 | 0.00 | A/B groups are not similar! | 327.01 | 396.92 | 16.00 | 19.00 |
| 0 | holiday_regional_Provincializacion_Santa_Elena | Non-Parametric | Fail to Reject H0 | 0.20 | A/B groups are similar! | 188.21 | 396.72 | 11.50 | 19.00 |
| 0 | holiday_regional_Provincializacion_de_Cotopaxi | Non-Parametric | Reject H0 | 0.00 | A/B groups are not similar! | 245.20 | 396.73 | 5.00 | 19.00 |
| 0 | holiday_regional_Provincializacion_de_Imbabura | Non-Parametric | Reject H0 | 0.01 | A/B groups are not similar! | 182.07 | 396.72 | 9.00 | 19.00 |
| 0 | holiday_regional_Provincializacion_de_Santo_Do... | Non-Parametric | Fail to Reject H0 | 0.60 | A/B groups are similar! | 326.72 | 396.72 | 19.50 | 19.00 |
| 0 | holiday_local_Cantonizacion_de_Cayambe | Non-Parametric | Fail to Reject H0 | 0.11 | A/B groups are similar! | 459.53 | 396.71 | 24.50 | 19.00 |
| 0 | holiday_local_Cantonizacion_de_El_Carmen | Non-Parametric | Fail to Reject H0 | 0.07 | A/B groups are similar! | 235.88 | 396.72 | 17.50 | 19.00 |
| 0 | holiday_local_Cantonizacion_de_Guaranda | Non-Parametric | Reject H0 | 0.01 | A/B groups are not similar! | 183.58 | 396.72 | 8.00 | 19.00 |
| 0 | holiday_local_Cantonizacion_de_Latacunga | Non-Parametric | Reject H0 | 0.00 | A/B groups are not similar! | 188.05 | 396.73 | 12.00 | 19.00 |
| 0 | holiday_local_Cantonizacion_de_Libertad | Non-Parametric | Fail to Reject H0 | 0.28 | A/B groups are similar! | 297.36 | 396.71 | 12.00 | 19.00 |
| 0 | holiday_local_Cantonizacion_de_Quevedo | Non-Parametric | Fail to Reject H0 | 0.13 | A/B groups are similar! | 213.73 | 396.72 | 18.50 | 19.00 |
| 0 | holiday_local_Cantonizacion_de_Riobamba | Non-Parametric | Reject H0 | 0.00 | A/B groups are not similar! | 195.55 | 396.72 | 8.00 | 19.00 |
| 0 | holiday_local_Cantonizacion_de_Salinas | Non-Parametric | Fail to Reject H0 | 0.80 | A/B groups are similar! | 285.65 | 396.72 | 19.50 | 19.00 |
| 0 | holiday_local_Cantonizacion_del_Puyo | Non-Parametric | Fail to Reject H0 | 0.33 | A/B groups are similar! | 150.41 | 396.72 | 23.00 | 19.00 |
| 0 | holiday_local_Fundacion_de_Ambato | Non-Parametric | Fail to Reject H0 | 0.87 | A/B groups are similar! | 336.04 | 396.72 | 21.60 | 19.00 |
| 0 | holiday_local_Fundacion_de_Cuenca | Non-Parametric | Fail to Reject H0 | 0.92 | A/B groups are similar! | 333.86 | 396.72 | 19.00 | 19.00 |
| 0 | holiday_local_Fundacion_de_Esmeraldas | Non-Parametric | Fail to Reject H0 | 0.23 | A/B groups are similar! | 333.56 | 396.71 | 10.00 | 19.00 |
| 0 | holiday_local_Fundacion_de_Guayaquil | Non-Parametric | Reject H0 | 0.00 | A/B groups are not similar! | 288.48 | 396.80 | 14.00 | 19.00 |
| 0 | holiday_local_Fundacion_de_Ibarra | Non-Parametric | Fail to Reject H0 | 0.05 | A/B groups are similar! | 224.81 | 396.72 | 7.50 | 19.00 |
| 0 | holiday_local_Fundacion_de_Loja | Non-Parametric | Fail to Reject H0 | 0.26 | A/B groups are similar! | 441.52 | 396.71 | 20.00 | 19.00 |
| 0 | holiday_local_Fundacion_de_Machala | Non-Parametric | Fail to Reject H0 | 0.50 | A/B groups are similar! | 297.36 | 396.72 | 17.00 | 19.00 |
| 0 | holiday_local_Fundacion_de_Manta | Non-Parametric | Fail to Reject H0 | 0.63 | A/B groups are similar! | 255.17 | 396.72 | 15.00 | 19.00 |
| 0 | holiday_local_Fundacion_de_Quito | Non-Parametric | Reject H0 | 0.00 | A/B groups are not similar! | 732.59 | 396.15 | 41.00 | 19.00 |
| 0 | holiday_local_Fundacion_de_Riobamba | Non-Parametric | Reject H0 | 0.00 | A/B groups are not similar! | 193.41 | 396.72 | 3.00 | 19.00 |
| 0 | holiday_local_Fundacion_de_Santo_Domingo | Non-Parametric | Fail to Reject H0 | 0.42 | A/B groups are similar! | 314.92 | 396.72 | 21.00 | 19.00 |
| 0 | holiday_local_Independencia_de_Ambato | Non-Parametric | Fail to Reject H0 | 0.13 | A/B groups are similar! | 370.56 | 396.71 | 29.50 | 19.00 |
| 0 | holiday_local_Independencia_de_Guaranda | Non-Parametric | Fail to Reject H0 | 0.06 | A/B groups are similar! | 219.94 | 396.72 | 6.00 | 19.00 |
| 0 | holiday_local_Independencia_de_Latacunga | Non-Parametric | Reject H0 | 0.00 | A/B groups are not similar! | 178.59 | 396.73 | 11.00 | 19.00 |
| 0 | national_independence | Non-Parametric | Reject H0 | 0.00 | A/B groups are not similar! | 457.03 | 396.07 | 23.00 | 19.00 |
| 0 | local_cantonizacio | Non-Parametric | Reject H0 | 0.00 | A/B groups are not similar! | 396.33 | 506.69 | 19.00 | 26.00 |
| 0 | local_fundacion | Non-Parametric | Reject H0 | 0.00 | A/B groups are not similar! | 396.82 | 250.79 | 19.00 | 14.00 |
| 0 | local_independencia | Non-Parametric | Reject H0 | 0.00 | A/B groups are not similar! | 396.38 | 486.04 | 19.00 | 25.00 |
d.groupby(["family","events_Futbol"]).sales.mean()[:60]
family events_Futbol
AUTOMOTIVE 0 6.59
1 6.20
BABY CARE 0 0.15
1 0.09
BEAUTY 0 4.02
1 2.89
BEVERAGES 0 2577.73
1 2243.45
BOOKS 0 0.15
1 0.00
BREAD/BAKERY 0 500.48
1 451.53
CELEBRATION 0 9.06
1 6.43
CLEANING 0 1157.94
1 1102.08
DAIRY 0 765.46
1 759.26
DELI 0 286.35
1 264.20
EGGS 0 185.05
1 180.72
FROZEN FOODS 0 167.31
1 134.66
GROCERY I 0 4079.68
1 3695.02
GROCERY II 0 23.30
1 22.24
HARDWARE 0 1.23
1 1.22
HOME AND KITCHEN I 0 22.16
1 13.94
HOME AND KITCHEN II 0 18.14
1 6.19
HOME APPLIANCES 0 0.49
1 0.44
HOME CARE 0 190.43
1 159.24
LADIESWEAR 0 9.54
1 9.70
LAWN AND GARDEN 0 6.94
1 5.05
LINGERIE 0 7.74
1 8.83
LIQUOR,WINE,BEER 0 91.76
1 115.06
MAGAZINES 0 3.18
1 0.49
MEATS 0 368.91
1 376.27
PERSONAL CARE 0 292.03
1 274.46
PET SUPPLIES 0 4.24
1 2.72
PLAYERS AND ELECTRONICS 0 6.69
1 4.57
POULTRY 0 377.97
1 424.07
PREPARED FOODS 0 104.43
1 106.65
Name: sales, dtype: float32
Ta có thể tạo bao nhiêu tính năng chỉ từ cột ngày? Dưới đây là một ví dụ về các thuộc tính liên quan đến thời gian.
# Time Related Features
def create_date_features(df):
df['month'] = df.date.dt.month.astype("int8")
df['day_of_month'] = df.date.dt.day.astype("int8")
df['day_of_year'] = df.date.dt.dayofyear.astype("int16")
df['week_of_month'] = (df.date.apply(lambda d: (d.day-1) // 7 + 1)).astype("int8")
df['week_of_year'] = (df.date.dt.weekofyear).astype("int8")
df['day_of_week'] = (df.date.dt.dayofweek + 1).astype("int8")
df['year'] = df.date.dt.year.astype("int32")
df["is_wknd"] = (df.date.dt.weekday // 4).astype("int8")
df["quarter"] = df.date.dt.quarter.astype("int8")
df['is_month_start'] = df.date.dt.is_month_start.astype("int8")
df['is_month_end'] = df.date.dt.is_month_end.astype("int8")
df['is_quarter_start'] = df.date.dt.is_quarter_start.astype("int8")
df['is_quarter_end'] = df.date.dt.is_quarter_end.astype("int8")
df['is_year_start'] = df.date.dt.is_year_start.astype("int8")
df['is_year_end'] = df.date.dt.is_year_end.astype("int8")
# 0: Winter - 1: Spring - 2: Summer - 3: Fall
df["season"] = np.where(df.month.isin([12,1,2]), 0, 1)
df["season"] = np.where(df.month.isin([6,7,8]), 2, df["season"])
df["season"] = pd.Series(np.where(df.month.isin([9, 10, 11]), 3, df["season"])).astype("int8")
return df
d = create_date_features(d)
# Workday column
d["workday"] = np.where((d.holiday_national_binary == 1) | (d.holiday_local_binary==1) | (d.holiday_regional_binary==1) | (d['day_of_week'].isin([6,7])), 0, 1)
d["workday"] = pd.Series(np.where(d.IsWorkDay.notnull(), 1, d["workday"])).astype("int8")
d.drop("IsWorkDay", axis = 1, inplace = True)
# Wages in the public sector are paid every two weeks on the 15 th and on the last day of the month.
# Supermarket sales could be affected by this.
d["wageday"] = pd.Series(np.where((d['is_month_end'] == 1) | (d["day_of_month"] == 15), 1, 0)).astype("int8")
d.head(15)
| id | date | store_nbr | family | sales | onpromotion | city | state | type | cluster | events_Black_Friday | events_Cyber_Monday | events_Dia_de_la_Madre | events_Futbol | events_Terremoto_Manabi | holiday_national_binary | holiday_local_binary | holiday_regional_binary | national_independence | local_cantonizacio | local_fundacion | local_independencia | holiday_national_Batalla_de_Pichincha | holiday_national_Carnaval | holiday_national_Dia_de_Difuntos | holiday_national_Dia_de_la_Madre | holiday_national_Dia_del_Trabajo | holiday_national_Independencia_de_Cuenca | holiday_national_Independencia_de_Guayaquil | holiday_national_Navidad | holiday_national_Primer_Grito_de_Independencia | holiday_national_Primer_dia_del_ano | holiday_national_Viernes_Santo | holiday_regional_Provincializacion_Santa_Elena | holiday_regional_Provincializacion_de_Cotopaxi | holiday_regional_Provincializacion_de_Imbabura | holiday_regional_Provincializacion_de_Santo_Domingo | holiday_local_Cantonizacion_de_Cayambe | holiday_local_Cantonizacion_de_El_Carmen | holiday_local_Cantonizacion_de_Guaranda | holiday_local_Cantonizacion_de_Latacunga | holiday_local_Cantonizacion_de_Libertad | holiday_local_Cantonizacion_de_Quevedo | holiday_local_Cantonizacion_de_Riobamba | holiday_local_Cantonizacion_de_Salinas | holiday_local_Cantonizacion_del_Puyo | holiday_local_Fundacion_de_Ambato | holiday_local_Fundacion_de_Cuenca | holiday_local_Fundacion_de_Esmeraldas | holiday_local_Fundacion_de_Guayaquil | holiday_local_Fundacion_de_Ibarra | holiday_local_Fundacion_de_Loja | holiday_local_Fundacion_de_Machala | holiday_local_Fundacion_de_Manta | holiday_local_Fundacion_de_Quito | holiday_local_Fundacion_de_Riobamba | holiday_local_Fundacion_de_Santo_Domingo | holiday_local_Independencia_de_Ambato | holiday_local_Independencia_de_Guaranda | holiday_local_Independencia_de_Latacunga | month | day_of_month | day_of_year | week_of_month | week_of_year | day_of_week | year | is_wknd | quarter | is_month_start | is_month_end | is_quarter_start | is_quarter_end | is_year_start | is_year_end | season | workday | wageday | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 0 | 2013-01-01 | 1 | AUTOMOTIVE | 0.00 | 0.00 | Quito | Pichincha | D | 13 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 2 | 2013 | 0 | 1 | 1 | 0 | 1 | 0 | 1 | 0 | 0 | 0 | 0 |
| 1 | 1782 | 2013-01-02 | 1 | AUTOMOTIVE | 2.00 | 0.00 | Quito | Pichincha | D | 13 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 2 | 2 | 1 | 1 | 3 | 2013 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
| 2 | 3564 | 2013-01-03 | 1 | AUTOMOTIVE | 3.00 | 0.00 | Quito | Pichincha | D | 13 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 3 | 3 | 1 | 1 | 4 | 2013 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
| 3 | 5346 | 2013-01-04 | 1 | AUTOMOTIVE | 3.00 | 0.00 | Quito | Pichincha | D | 13 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 4 | 4 | 1 | 1 | 5 | 2013 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
| 4 | 7128 | 2013-01-05 | 1 | AUTOMOTIVE | 5.00 | 0.00 | Quito | Pichincha | D | 13 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 5 | 5 | 1 | 1 | 6 | 2013 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
| 5 | 8910 | 2013-01-06 | 1 | AUTOMOTIVE | 2.00 | 0.00 | Quito | Pichincha | D | 13 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 6 | 6 | 1 | 1 | 7 | 2013 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 6 | 10692 | 2013-01-07 | 1 | AUTOMOTIVE | 0.00 | 0.00 | Quito | Pichincha | D | 13 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 7 | 7 | 1 | 2 | 1 | 2013 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
| 7 | 12474 | 2013-01-08 | 1 | AUTOMOTIVE | 2.00 | 0.00 | Quito | Pichincha | D | 13 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 8 | 8 | 2 | 2 | 2 | 2013 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
| 8 | 14256 | 2013-01-09 | 1 | AUTOMOTIVE | 2.00 | 0.00 | Quito | Pichincha | D | 13 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 9 | 9 | 2 | 2 | 3 | 2013 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
| 9 | 16038 | 2013-01-10 | 1 | AUTOMOTIVE | 2.00 | 0.00 | Quito | Pichincha | D | 13 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 10 | 10 | 2 | 2 | 4 | 2013 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
| 10 | 17820 | 2013-01-11 | 1 | AUTOMOTIVE | 3.00 | 0.00 | Quito | Pichincha | D | 13 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 11 | 11 | 2 | 2 | 5 | 2013 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
| 11 | 19602 | 2013-01-12 | 1 | AUTOMOTIVE | 2.00 | 0.00 | Quito | Pichincha | D | 13 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 12 | 12 | 2 | 2 | 6 | 2013 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
| 12 | 21384 | 2013-01-13 | 1 | AUTOMOTIVE | 2.00 | 0.00 | Quito | Pichincha | D | 13 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 13 | 13 | 2 | 2 | 7 | 2013 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 13 | 23166 | 2013-01-14 | 1 | AUTOMOTIVE | 2.00 | 0.00 | Quito | Pichincha | D | 13 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 14 | 14 | 2 | 3 | 1 | 2013 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
| 14 | 24948 | 2013-01-15 | 1 | AUTOMOTIVE | 1.00 | 0.00 | Quito | Pichincha | D | 13 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 15 | 15 | 3 | 3 | 2 | 2013 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 |
Động đất có ảnh hưởng đến doanh thu của cửa hàng không?
Một trận động đất mạnh 7,8 độ Richter đã xảy ra ở Ecuador vào ngày 16 tháng 4 năm 2016. Mọi người tập hợp trong các nỗ lực cứu trợ quyên góp nước và các sản phẩm cần thiết khác, điều này đã ảnh hưởng lớn đến doanh số bán hàng của siêu thị trong vài tuần sau trận động đất.
So sánh doanh số bán hàng trung bình theo năm, tháng và nhóm sản phẩm sẽ là một trong những cách tốt nhất để có thể hiểu trận động đất đã ảnh hưởng đến doanh thu của cửa hàng như thế nào.
Ta có thể sử dụng dữ liệu của tháng 3, tháng 4, tháng 5 và tháng 6 và doanh số bán hàng có thể tăng hoặc giảm đối với một số nhóm sản phẩm.
Cuối cùng, ta trích xuất một cột về động đất từ dữ liệu Ngày lễ và Sự kiện. cột "events_Terremoto_Manabi" sẽ giúp phù hợp với mô hình tốt hơn.
d[(d.month.isin([4,5]))].groupby(["year"]).sales.mean()
year 2013 249.38 2014 285.53 2015 334.68 2016 489.90 2017 503.50 Name: sales, dtype: float32
pd.pivot_table(d[(d.month.isin([3]))], index="year", columns="family", values="sales", aggfunc="mean")
| family | AUTOMOTIVE | BABY CARE | BEAUTY | BEVERAGES | BOOKS | BREAD/BAKERY | CELEBRATION | CLEANING | DAIRY | DELI | EGGS | FROZEN FOODS | GROCERY I | GROCERY II | HARDWARE | HOME AND KITCHEN I | HOME AND KITCHEN II | HOME APPLIANCES | HOME CARE | LADIESWEAR | LAWN AND GARDEN | LINGERIE | LIQUOR,WINE,BEER | MAGAZINES | MEATS | PERSONAL CARE | PET SUPPLIES | PLAYERS AND ELECTRONICS | POULTRY | PREPARED FOODS | PRODUCE | SCHOOL AND OFFICE SUPPLIES | SEAFOOD |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| year | |||||||||||||||||||||||||||||||||
| 2013 | 5.35 | 0.00 | 2.74 | 1277.85 | 0.00 | 416.57 | 0.00 | 1055.67 | 429.53 | 229.49 | 157.80 | 95.06 | 3281.80 | 20.69 | 1.11 | 0.00 | 0.00 | 0.80 | 0.00 | 0.00 | 3.31 | 9.33 | 74.50 | 0.00 | 368.54 | 223.88 | 0.00 | 0.00 | 223.56 | 106.08 | 2.83 | 0.00 | 28.10 |
| 2014 | 6.94 | 0.06 | 3.55 | 3040.63 | 0.00 | 446.92 | 14.74 | 1215.01 | 815.26 | 261.29 | 189.67 | 138.42 | 3807.03 | 21.25 | 1.50 | 23.82 | 12.52 | 0.71 | 297.74 | 16.65 | 5.63 | 8.49 | 95.85 | 1.34 | 382.59 | 265.75 | 5.50 | 11.02 | 449.17 | 112.42 | 2300.86 | 1.53 | 27.45 |
| 2015 | 7.55 | 0.00 | 2.78 | 1515.37 | 0.00 | 547.43 | 0.00 | 1219.26 | 806.57 | 329.61 | 209.24 | 129.68 | 4016.91 | 23.82 | 1.13 | 24.85 | 18.66 | 0.85 | 0.00 | 0.00 | 5.35 | 6.52 | 91.09 | 0.00 | 356.97 | 316.62 | 0.00 | 0.00 | 420.88 | 104.59 | 4.51 | 0.00 | 28.61 |
| 2016 | 7.34 | 0.34 | 4.34 | 3023.50 | 0.00 | 501.95 | 14.23 | 1077.72 | 859.32 | 277.81 | 177.58 | 131.25 | 4088.61 | 19.78 | 1.32 | 26.11 | 25.67 | 0.31 | 267.45 | 13.88 | 5.35 | 4.92 | 89.79 | 6.07 | 330.77 | 296.47 | 5.89 | 8.72 | 374.97 | 109.86 | 2304.82 | 1.96 | 23.89 |
| 2017 | 7.79 | 0.34 | 4.29 | 3733.14 | 0.59 | 584.24 | 14.21 | 1220.11 | 991.14 | 326.49 | 199.83 | 130.17 | 4800.77 | 22.14 | 1.45 | 29.23 | 29.95 | 0.71 | 319.10 | 14.74 | 15.97 | 6.88 | 89.70 | 6.28 | 374.28 | 331.43 | 8.79 | 11.39 | 395.35 | 114.03 | 2442.19 | 5.02 | 25.54 |
pd.pivot_table(d[(d.month.isin([4,5]))], index="year", columns="family", values="sales", aggfunc="mean")
| family | AUTOMOTIVE | BABY CARE | BEAUTY | BEVERAGES | BOOKS | BREAD/BAKERY | CELEBRATION | CLEANING | DAIRY | DELI | EGGS | FROZEN FOODS | GROCERY I | GROCERY II | HARDWARE | HOME AND KITCHEN I | HOME AND KITCHEN II | HOME APPLIANCES | HOME CARE | LADIESWEAR | LAWN AND GARDEN | LINGERIE | LIQUOR,WINE,BEER | MAGAZINES | MEATS | PERSONAL CARE | PET SUPPLIES | PLAYERS AND ELECTRONICS | POULTRY | PREPARED FOODS | PRODUCE | SCHOOL AND OFFICE SUPPLIES | SEAFOOD |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| year | |||||||||||||||||||||||||||||||||
| 2013 | 5.84 | 0.00 | 2.61 | 1260.96 | 0.00 | 418.76 | 0.00 | 1027.76 | 408.36 | 234.52 | 154.75 | 104.79 | 3308.63 | 21.95 | 1.01 | 0.00 | 0.00 | 0.75 | 0.00 | 0.00 | 3.23 | 9.39 | 71.10 | 0.00 | 377.75 | 224.65 | 0.00 | 0.00 | 221.59 | 96.68 | 5.35 | 0.00 | 25.37 |
| 2014 | 5.75 | 0.00 | 2.61 | 1461.64 | 0.00 | 416.34 | 0.00 | 1028.08 | 766.63 | 253.55 | 184.63 | 121.35 | 3614.11 | 21.44 | 1.02 | 0.00 | 0.00 | 0.56 | 0.00 | 0.00 | 4.98 | 8.94 | 85.83 | 0.00 | 361.61 | 266.44 | 0.00 | 0.00 | 405.27 | 103.47 | 5.66 | 0.00 | 23.63 |
| 2015 | 6.02 | 0.00 | 2.96 | 1915.16 | 0.00 | 551.60 | 0.00 | 1227.91 | 811.31 | 329.80 | 198.89 | 139.64 | 3989.90 | 26.46 | 1.06 | 26.11 | 20.73 | 0.65 | 127.72 | 0.00 | 5.47 | 8.20 | 95.21 | 1.69 | 365.24 | 314.39 | 0.06 | 0.00 | 415.49 | 102.44 | 5.68 | 0.00 | 27.05 |
| 2016 | 7.26 | 0.32 | 4.87 | 3369.27 | 0.00 | 551.90 | 14.25 | 1218.35 | 911.86 | 299.28 | 186.11 | 135.95 | 4898.71 | 22.04 | 1.36 | 27.10 | 28.28 | 0.45 | 315.92 | 14.96 | 5.47 | 6.24 | 82.89 | 6.77 | 363.50 | 363.47 | 6.84 | 10.67 | 399.37 | 108.67 | 2305.70 | 5.99 | 24.55 |
| 2017 | 7.63 | 0.23 | 5.30 | 3592.94 | 0.26 | 557.84 | 13.72 | 1308.01 | 970.85 | 323.21 | 202.54 | 138.61 | 4841.85 | 26.12 | 1.55 | 30.31 | 31.31 | 0.71 | 304.85 | 15.40 | 19.17 | 7.83 | 90.16 | 6.87 | 362.41 | 326.00 | 9.07 | 12.22 | 385.39 | 96.31 | 2404.91 | 11.71 | 23.17 |
pd.pivot_table(d[(d.month.isin([6]))], index="year", columns="family", values="sales", aggfunc="mean")
| family | AUTOMOTIVE | BABY CARE | BEAUTY | BEVERAGES | BOOKS | BREAD/BAKERY | CELEBRATION | CLEANING | DAIRY | DELI | EGGS | FROZEN FOODS | GROCERY I | GROCERY II | HARDWARE | HOME AND KITCHEN I | HOME AND KITCHEN II | HOME APPLIANCES | HOME CARE | LADIESWEAR | LAWN AND GARDEN | LINGERIE | LIQUOR,WINE,BEER | MAGAZINES | MEATS | PERSONAL CARE | PET SUPPLIES | PLAYERS AND ELECTRONICS | POULTRY | PREPARED FOODS | PRODUCE | SCHOOL AND OFFICE SUPPLIES | SEAFOOD |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| year | |||||||||||||||||||||||||||||||||
| 2013 | 5.89 | 0.00 | 2.72 | 1297.24 | 0.00 | 431.05 | 0.00 | 1052.44 | 419.08 | 238.23 | 156.45 | 120.79 | 3489.13 | 21.83 | 0.95 | 0.00 | 0.00 | 0.71 | 0.00 | 0.00 | 3.43 | 8.85 | 75.67 | 0.00 | 389.95 | 216.12 | 0.00 | 0.00 | 232.16 | 100.72 | 6.12 | 0.00 | 20.99 |
| 2014 | 5.72 | 0.00 | 2.46 | 1458.94 | 0.00 | 450.82 | 0.00 | 1029.45 | 757.82 | 260.01 | 182.69 | 122.18 | 3655.15 | 22.99 | 1.03 | 0.00 | 0.00 | 0.41 | 0.00 | 0.00 | 4.35 | 8.60 | 94.37 | 0.00 | 383.37 | 270.10 | 0.00 | 0.00 | 409.03 | 101.04 | 5.75 | 0.00 | 23.97 |
| 2015 | 6.52 | 0.18 | 3.79 | 3178.15 | 0.00 | 549.95 | 14.74 | 1177.30 | 829.06 | 328.15 | 196.27 | 139.39 | 3903.51 | 25.12 | 1.30 | 26.92 | 31.28 | 0.12 | 288.21 | 16.89 | 5.27 | 7.83 | 101.28 | 1.53 | 376.68 | 297.36 | 5.87 | 8.72 | 411.02 | 108.23 | 2346.14 | 1.33 | 25.85 |
| 2016 | 6.25 | 0.35 | 4.55 | 2806.97 | 0.00 | 550.81 | 13.96 | 1108.43 | 863.92 | 280.66 | 182.98 | 129.32 | 4170.43 | 21.84 | 1.08 | 28.62 | 25.08 | 0.29 | 260.83 | 14.07 | 5.66 | 4.43 | 85.12 | 5.67 | 350.66 | 292.74 | 5.95 | 8.50 | 373.23 | 104.96 | 2239.03 | 1.55 | 23.18 |
| 2017 | 7.38 | 0.23 | 5.43 | 3580.13 | 0.08 | 555.64 | 13.80 | 1228.70 | 932.53 | 317.70 | 202.11 | 137.49 | 4702.43 | 29.26 | 1.40 | 33.93 | 30.85 | 0.64 | 286.55 | 14.65 | 17.85 | 6.78 | 95.40 | 6.19 | 388.38 | 319.44 | 9.22 | 11.34 | 406.58 | 90.90 | 2403.45 | 1.58 | 19.36 |
Tính trễ có nghĩa là dịch chuyển thời gian về phía trước một bước hoặc nhiều hơn một bước. Vì vậy, độ trễ có thể sử dụng trong mô hình để cải thiện nó. Tuy nhiên, có bao nhiêu tính trễ bên trong mô hình? Để hiểu điều đó, chúng ta có thể sử dụng ACF và PACF. PACF rất hữu ích để quyết định tính năng nào nên chọn.
Trong bài toán của chúng ta, chúng ta có nhiều chuỗi thời gian và tất nhiên mỗi chuỗi thời gian có các mẫu khác nhau. Bạn biết rằng chuỗi thời gian đó bao gồm các tổ hợp cửa hàng-sản phẩm và chúng tôi có 54 cửa hàng và 33 họ sản phẩm. Chúng tôi không thể kiểm tra tất cả từng cái một. Vì lý do này, tôi sẽ xem xét doanh số trung bình cho từng sản phẩm nhưng nó sẽ độc lập với cửa hàng.
Ngoài ra, dữ liệu thử nghiệm chứa 15 ngày cho mỗi gia đình. Chúng ta nên cẩn thận khi lựa chọn các tính năng có độ trễ. Ta không thể tạo các thuộc tính độ trễ mới từ độ trễ 1 đến độ trễ 15. Thuộc tính này cần được bắt đầu từ 16.
#a = d[d["store_nbr"]==1].set_index("date")
a = d[(d.sales.notnull())].groupby(["date", "family"]).sales.mean().reset_index().set_index("date")
for num, i in enumerate(a.family.unique()):
try:
fig, ax = plt.subplots(1,2,figsize=(15,5))
temp = a[(a.family == i)]#& (a.sales.notnull())
sm.graphics.tsa.plot_acf(temp.sales, lags=365, ax=ax[0], title = "AUTOCORRELATION\n" + i)
sm.graphics.tsa.plot_pacf(temp.sales, lags=365, ax=ax[1], title = "PARTIAL AUTOCORRELATION\n" + i)
except:
pass
Ta quyết định chọn các độ trễ 16, 20, 30, 45, 365, 730 từ PACF. Ta không biết rằng chúng sẽ giúp cải thiện mô hình nhưng độ trễ thứ 365 và 730 có thể hữu ích. Nếu so sánh giữa năm 2016 và 2017 về doanh số, ta có thể thấy rằng chúng có mối tương quan cao.
a = d[d.year.isin([2016,2017])].groupby(["year", "day_of_year"]).sales.mean().reset_index()
px.line(a, x = "day_of_year", y = "sales", color = "year", title = "Average sales for 2016 and 2017")
a = train.sort_values(["store_nbr", "family", "date"])
for i in [20, 30, 45, 60, 90, 120, 365, 730]:
a["SMA"+str(i)+"_sales_lag16"] = a.groupby(["store_nbr", "family"]).rolling(i).sales.mean().shift(16).values
a["SMA"+str(i)+"_sales_lag30"] = a.groupby(["store_nbr", "family"]).rolling(i).sales.mean().shift(30).values
a["SMA"+str(i)+"_sales_lag60"] = a.groupby(["store_nbr", "family"]).rolling(i).sales.mean().shift(60).values
print("Correlation")
a[["sales"]+a.columns[a.columns.str.startswith("SMA")].tolist()].corr()
Correlation
| sales | SMA20_sales_lag16 | SMA20_sales_lag30 | SMA20_sales_lag60 | SMA30_sales_lag16 | SMA30_sales_lag30 | SMA30_sales_lag60 | SMA45_sales_lag16 | SMA45_sales_lag30 | SMA45_sales_lag60 | SMA60_sales_lag16 | SMA60_sales_lag30 | SMA60_sales_lag60 | SMA90_sales_lag16 | SMA90_sales_lag30 | SMA90_sales_lag60 | SMA120_sales_lag16 | SMA120_sales_lag30 | SMA120_sales_lag60 | SMA365_sales_lag16 | SMA365_sales_lag30 | SMA365_sales_lag60 | SMA730_sales_lag16 | SMA730_sales_lag30 | SMA730_sales_lag60 | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| sales | 1.00 | 0.91 | 0.89 | 0.87 | 0.91 | 0.89 | 0.87 | 0.91 | 0.90 | 0.87 | 0.91 | 0.89 | 0.87 | 0.91 | 0.89 | 0.87 | 0.90 | 0.89 | 0.86 | 0.90 | 0.89 | 0.87 | 0.91 | 0.89 | 0.86 |
| SMA20_sales_lag16 | 0.91 | 1.00 | 0.99 | 0.95 | 1.00 | 0.98 | 0.95 | 0.99 | 0.98 | 0.95 | 0.99 | 0.98 | 0.95 | 0.99 | 0.98 | 0.95 | 0.98 | 0.97 | 0.95 | 0.97 | 0.97 | 0.95 | 0.98 | 0.98 | 0.95 |
| SMA20_sales_lag30 | 0.89 | 0.99 | 1.00 | 0.96 | 0.99 | 1.00 | 0.96 | 1.00 | 0.99 | 0.97 | 0.99 | 0.99 | 0.97 | 0.99 | 0.99 | 0.96 | 0.99 | 0.98 | 0.96 | 0.97 | 0.97 | 0.96 | 0.98 | 0.98 | 0.96 |
| SMA20_sales_lag60 | 0.87 | 0.95 | 0.96 | 1.00 | 0.96 | 0.98 | 1.00 | 0.98 | 0.99 | 0.99 | 0.99 | 0.99 | 0.99 | 0.99 | 0.99 | 0.99 | 0.99 | 0.99 | 0.98 | 0.98 | 0.97 | 0.97 | 0.98 | 0.98 | 0.98 |
| SMA30_sales_lag16 | 0.91 | 1.00 | 0.99 | 0.96 | 1.00 | 0.99 | 0.96 | 1.00 | 0.99 | 0.96 | 0.99 | 0.99 | 0.96 | 0.99 | 0.98 | 0.96 | 0.99 | 0.98 | 0.96 | 0.98 | 0.97 | 0.96 | 0.98 | 0.98 | 0.96 |
| SMA30_sales_lag30 | 0.89 | 0.98 | 1.00 | 0.98 | 0.99 | 1.00 | 0.98 | 1.00 | 1.00 | 0.98 | 1.00 | 0.99 | 0.98 | 0.99 | 0.99 | 0.97 | 0.99 | 0.99 | 0.97 | 0.98 | 0.98 | 0.97 | 0.98 | 0.98 | 0.98 |
| SMA30_sales_lag60 | 0.87 | 0.95 | 0.96 | 1.00 | 0.96 | 0.98 | 1.00 | 0.98 | 0.99 | 1.00 | 0.99 | 0.99 | 0.99 | 0.99 | 0.99 | 0.99 | 0.99 | 0.99 | 0.99 | 0.98 | 0.98 | 0.98 | 0.98 | 0.98 | 0.98 |
| SMA45_sales_lag16 | 0.91 | 0.99 | 1.00 | 0.98 | 1.00 | 1.00 | 0.98 | 1.00 | 1.00 | 0.98 | 1.00 | 0.99 | 0.98 | 0.99 | 0.99 | 0.98 | 0.99 | 0.99 | 0.97 | 0.98 | 0.98 | 0.97 | 0.98 | 0.98 | 0.98 |
| SMA45_sales_lag30 | 0.90 | 0.98 | 0.99 | 0.99 | 0.99 | 1.00 | 0.99 | 1.00 | 1.00 | 0.99 | 1.00 | 1.00 | 0.99 | 1.00 | 0.99 | 0.98 | 0.99 | 0.99 | 0.98 | 0.98 | 0.98 | 0.98 | 0.98 | 0.98 | 0.98 |
| SMA45_sales_lag60 | 0.87 | 0.95 | 0.97 | 0.99 | 0.96 | 0.98 | 1.00 | 0.98 | 0.99 | 1.00 | 0.99 | 0.99 | 1.00 | 0.99 | 1.00 | 0.99 | 0.99 | 0.99 | 0.99 | 0.98 | 0.98 | 0.98 | 0.98 | 0.98 | 0.98 |
| SMA60_sales_lag16 | 0.91 | 0.99 | 0.99 | 0.99 | 0.99 | 1.00 | 0.99 | 1.00 | 1.00 | 0.99 | 1.00 | 1.00 | 0.99 | 1.00 | 0.99 | 0.98 | 0.99 | 0.99 | 0.98 | 0.98 | 0.98 | 0.98 | 0.98 | 0.98 | 0.98 |
| SMA60_sales_lag30 | 0.89 | 0.98 | 0.99 | 0.99 | 0.99 | 0.99 | 0.99 | 0.99 | 1.00 | 0.99 | 1.00 | 1.00 | 0.99 | 1.00 | 1.00 | 0.99 | 1.00 | 0.99 | 0.98 | 0.98 | 0.98 | 0.98 | 0.98 | 0.98 | 0.98 |
| SMA60_sales_lag60 | 0.87 | 0.95 | 0.97 | 0.99 | 0.96 | 0.98 | 0.99 | 0.98 | 0.99 | 1.00 | 0.99 | 0.99 | 1.00 | 0.99 | 1.00 | 1.00 | 1.00 | 1.00 | 0.99 | 0.99 | 0.99 | 0.98 | 0.98 | 0.98 | 0.98 |
| SMA90_sales_lag16 | 0.91 | 0.99 | 0.99 | 0.99 | 0.99 | 0.99 | 0.99 | 0.99 | 1.00 | 0.99 | 1.00 | 1.00 | 0.99 | 1.00 | 1.00 | 0.99 | 1.00 | 1.00 | 0.99 | 0.99 | 0.99 | 0.98 | 0.99 | 0.98 | 0.98 |
| SMA90_sales_lag30 | 0.89 | 0.98 | 0.99 | 0.99 | 0.98 | 0.99 | 0.99 | 0.99 | 0.99 | 1.00 | 0.99 | 1.00 | 1.00 | 1.00 | 1.00 | 0.99 | 1.00 | 1.00 | 0.99 | 0.99 | 0.99 | 0.98 | 0.98 | 0.99 | 0.98 |
| SMA90_sales_lag60 | 0.87 | 0.95 | 0.96 | 0.99 | 0.96 | 0.97 | 0.99 | 0.98 | 0.98 | 0.99 | 0.98 | 0.99 | 1.00 | 0.99 | 0.99 | 1.00 | 1.00 | 1.00 | 1.00 | 0.99 | 0.99 | 0.99 | 0.98 | 0.98 | 0.99 |
| SMA120_sales_lag16 | 0.90 | 0.98 | 0.99 | 0.99 | 0.99 | 0.99 | 0.99 | 0.99 | 0.99 | 0.99 | 0.99 | 1.00 | 1.00 | 1.00 | 1.00 | 1.00 | 1.00 | 1.00 | 0.99 | 0.99 | 0.99 | 0.99 | 0.99 | 0.99 | 0.99 |
| SMA120_sales_lag30 | 0.89 | 0.97 | 0.98 | 0.99 | 0.98 | 0.99 | 0.99 | 0.99 | 0.99 | 0.99 | 0.99 | 0.99 | 1.00 | 1.00 | 1.00 | 1.00 | 1.00 | 1.00 | 1.00 | 0.99 | 0.99 | 0.99 | 0.99 | 0.99 | 0.99 |
| SMA120_sales_lag60 | 0.86 | 0.95 | 0.96 | 0.98 | 0.96 | 0.97 | 0.99 | 0.97 | 0.98 | 0.99 | 0.98 | 0.98 | 0.99 | 0.99 | 0.99 | 1.00 | 0.99 | 1.00 | 1.00 | 0.99 | 0.99 | 0.99 | 0.99 | 0.99 | 0.99 |
| SMA365_sales_lag16 | 0.90 | 0.97 | 0.97 | 0.98 | 0.98 | 0.98 | 0.98 | 0.98 | 0.98 | 0.98 | 0.98 | 0.98 | 0.99 | 0.99 | 0.99 | 0.99 | 0.99 | 0.99 | 0.99 | 1.00 | 1.00 | 1.00 | 1.00 | 1.00 | 1.00 |
| SMA365_sales_lag30 | 0.89 | 0.97 | 0.97 | 0.97 | 0.97 | 0.98 | 0.98 | 0.98 | 0.98 | 0.98 | 0.98 | 0.98 | 0.99 | 0.99 | 0.99 | 0.99 | 0.99 | 0.99 | 0.99 | 1.00 | 1.00 | 1.00 | 1.00 | 1.00 | 1.00 |
| SMA365_sales_lag60 | 0.87 | 0.95 | 0.96 | 0.97 | 0.96 | 0.97 | 0.98 | 0.97 | 0.98 | 0.98 | 0.98 | 0.98 | 0.98 | 0.98 | 0.98 | 0.99 | 0.99 | 0.99 | 0.99 | 1.00 | 1.00 | 1.00 | 1.00 | 1.00 | 1.00 |
| SMA730_sales_lag16 | 0.91 | 0.98 | 0.98 | 0.98 | 0.98 | 0.98 | 0.98 | 0.98 | 0.98 | 0.98 | 0.98 | 0.98 | 0.98 | 0.99 | 0.98 | 0.98 | 0.99 | 0.99 | 0.99 | 1.00 | 1.00 | 1.00 | 1.00 | 1.00 | 1.00 |
| SMA730_sales_lag30 | 0.89 | 0.98 | 0.98 | 0.98 | 0.98 | 0.98 | 0.98 | 0.98 | 0.98 | 0.98 | 0.98 | 0.98 | 0.98 | 0.98 | 0.99 | 0.98 | 0.99 | 0.99 | 0.99 | 1.00 | 1.00 | 1.00 | 1.00 | 1.00 | 1.00 |
| SMA730_sales_lag60 | 0.86 | 0.95 | 0.96 | 0.98 | 0.96 | 0.98 | 0.98 | 0.98 | 0.98 | 0.98 | 0.98 | 0.98 | 0.98 | 0.98 | 0.98 | 0.99 | 0.99 | 0.99 | 0.99 | 1.00 | 1.00 | 1.00 | 1.00 | 1.00 | 1.00 |
b = a[(a.store_nbr == 1)].set_index("date")
for i in b.family.unique():
fig, ax = plt.subplots(2,4,figsize=(20,10))
b[b.family == i][["sales", "SMA20_sales_lag16"]].plot(legend = True, ax = ax[0,0], linewidth = 4)
b[b.family == i][["sales", "SMA30_sales_lag16"]].plot(legend = True, ax = ax[0,1], linewidth = 4)
b[b.family == i][["sales", "SMA45_sales_lag16"]].plot(legend = True, ax = ax[0,2], linewidth = 4)
b[b.family == i][["sales", "SMA60_sales_lag16"]].plot(legend = True, ax = ax[0,3], linewidth = 4)
b[b.family == i][["sales", "SMA90_sales_lag16"]].plot(legend = True, ax = ax[1,0], linewidth = 4)
b[b.family == i][["sales", "SMA120_sales_lag16"]].plot(legend = True, ax = ax[1,1], linewidth = 4)
b[b.family == i][["sales", "SMA365_sales_lag16"]].plot(legend = True, ax = ax[1,2], linewidth = 4)
b[b.family == i][["sales", "SMA730_sales_lag16"]].plot(legend = True, ax = ax[1,3], linewidth = 4)
plt.suptitle("STORE 1 - "+i, fontsize = 15)
plt.tight_layout(pad = 1.5)
for j in range(0,4):
ax[0,j].legend(fontsize="x-large")
ax[1,j].legend(fontsize="x-large")
plt.show()
def ewm_features(dataframe, alphas, lags):
dataframe = dataframe.copy()
for alpha in alphas:
for lag in lags:
dataframe['sales_ewm_alpha_' + str(alpha).replace(".", "") + "_lag_" + str(lag)] = \
dataframe.groupby(["store_nbr", "family"])['sales']. \
transform(lambda x: x.shift(lag).ewm(alpha=alpha).mean())
return dataframe
alphas = [0.95, 0.9, 0.8, 0.7, 0.5]
lags = [16, 30, 60, 90]
a = ewm_features(a, alphas, lags)
a[(a.store_nbr == 1) & (a.family == "GROCERY I")].set_index("date")[["sales", "sales_ewm_alpha_095_lag_16"]].plot(title = "STORE 1 - GROCERY I");